#ifndef MEMORY_H
#define MEMORY_H

#include "comm/types.h"
#include "comm/boot_info.h"
#include "tools/bitmap.h"
#include "ipc/mutex.h"

#define MEM_EXT_START           0x100000            // 程序被加载到内存1mb以上
#define MEM_EXT_END             (127 * 1024 * 1024) // 程序被加载后可用的最大内存
#define MEM_PAGE_SIZE           4096
#define MEM_EBDA_START          0x80000             // bios的EBDA区域开始地址
#define MEMORY_TASK_BASE        0x80000000          // 规定每个用户任务的虚拟地址空间是从0x80000000开始的，操作系统则使用0～0x80000000-1处的虚拟内存
#define MEM_TASK_STACK_TOP      0xE0000000
#define MEM_TASK_STACK_SIZE     (MEM_PAGE_SIZE * 500)
#define MEM_TASK_ARG_SIZE       (MEM_PAGE_SIZE * 4)


typedef struct _addr_alloc_t {
    mutex_t mutex;
    bitmap_t bitmap;
    
    uint32_t start;
    uint32_t size;
    uint32_t page_size;
} addr_alloc_t;

typedef struct _memory_map_t {
    void *vstart;           // 内存映射——虚拟地址，起始地址
    void *vend;             // 内存映射——虚拟地址，结束地址
    void *pstart;           // 内存映射——被映射到物理地址的开始地址
    uint32_t perm;          // 内存映射——权限标志位
} memory_map_t;


void memory_init(boot_info_t *boot_info);
uint32_t memory_create_uvm(void);

// 给当前进程进行页表分配
// 分配虚拟地址空间并把虚拟空间映射到实际的物理空间
// addr虚拟地址空间开始地址，size是分配的空间大小，perm映射的物理空间的访问属性
int memory_alloc_page_for(uint32_t addr, uint32_t size, uint32_t perm);
int memory_alloc_for_page_dir(uint32_t page_dir, uint32_t vaddr, uint32_t size, int perm);
uint32_t memory_alloc_page();
void memory_free_page(uint32_t addr);
uint32_t memory_copy_uvm(uint32_t page_dir);
void memory_destory_uvm(uint32_t page_dir);
uint32_t memory_get_paddr (uint32_t page_dir, uint32_t vaddr);  // 根据页目录表和页表返回物理地址
int memory_copy_uvm_data(uint32_t to, uint32_t page_dir, uint32_t from, uint32_t size);
char * sys_sbrk(int incr);

#endif